package com.icim.xmtm5.exporter.service;

import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

import javax.annotation.Resource;

import org.apache.commons.lang.StringUtils;
import org.eclipse.jetty.util.StringUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.stereotype.Service;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.DefaultTransactionDefinition;

import com.icim.csot.exporter.tx.csotshipping.CsotShippingO;
import com.icim.dao.BisDataDao;
import com.icim.dao.HisRetPrdInfoDao;
import com.icim.dao.RetBoxDao;
import com.icim.dao.RetPrdInfoDao;
import com.icim.dao.RetPrdJgeDao;
import com.icim.dao.RetTmCusPrdInDao;
import com.icim.dao.RetTmCusPrdIndtDao;
import com.icim.dao.RetWoDao;
import com.icim.dao.SpcRetMfgDataDao;
import com.icim.entity.Bis_data;
import com.icim.entity.His_ret_prd_info;
import com.icim.entity.Ret_box;
import com.icim.entity.Ret_prd_info;
import com.icim.entity.Ret_prd_jge;
import com.icim.entity.Ret_tm_cus_prd_in;
import com.icim.entity.Ret_tm_cus_prd_indt;
import com.icim.entity.Ret_wo;
import com.icim.entity.Spc_ret_mfg_data;
import com.icim.exception.ICIMException;
import com.icim.util.TimeUtil;
import com.icim.xmtm5.dao.CtSlimifRetBox5Dao;
import com.icim.xmtm5.dao.CtSlimifRetDefectData5Dao;
import com.icim.xmtm5.dao.CtSlimifRetProduct5Dao;
import com.icim.xmtm.dao.CtSlimifRetTrackHistoryDao;
import com.icim.xmtm5.entity.CtSlimifRetBox5;
import com.icim.xmtm5.entity.CtSlimifRetDefectData5;
import com.icim.xmtm5.entity.CtSlimifRetProduct5;
import com.icim.xmtm.entity.CtSlimifRetTrackHistory;

import static com.icim.def.ComDef.*;

@Service
public class Xmtm5ExportShippingDataService implements IXmtm5ExportShippingDataService {


	private static List<String> mesIdList = new ArrayList<String>();
	private final static Logger logger  = LoggerFactory.getLogger(Xmtm5ExportShippingDataService.class);

	@Resource
	private RetBoxDao retBoxDao;

	@Resource
	private RetPrdInfoDao retPrdInfoDao;

	@Resource
	private RetPrdJgeDao retPrdJgeDao;

	@Resource
	private CtSlimifRetBox5Dao ctSlimifRetBox5Dao;

	@Resource
	private CtSlimifRetProduct5Dao ctSlimifRetProduct5Dao;

	@Resource
	private CtSlimifRetTrackHistoryDao ctSlimifRetTrackHistoryDao;
	
	
	@Resource
	private CtSlimifRetDefectData5Dao ctSlimifRetDefectData5Dao;

	@Resource
	private BisDataDao bisDataDao;

	@Resource
	private RetWoDao retWoDao;

	@Resource
	private RetTmCusPrdInDao retTmCusPrdInDao;

	@Resource
	private RetTmCusPrdIndtDao retTmCusPrdIndtDao;

	@Resource
	private SpcRetMfgDataDao spcRetMfgDataDao;

	@Resource
	private HisRetPrdInfoDao hisRetPrdInfoDao;

	@Resource
	DataSourceTransactionManager xmtm5TransactionManager;

	static {
		mesIdList.add("CDPC");
		mesIdList.add("CZPC");
	}

	@Override
	public CsotShippingO sendShippingData(String palletId) throws Exception {

		CsotShippingO outTrx = new CsotShippingO();
		List<Ret_box> boxList = retBoxDao.getBoxList(palletId);
		Timestamp currentTimestamp = TimeUtil.getCurrentTimestamp();

		
		Map<String, Bis_data> defectMap = getDefectMap(boxList);

		String woId = null;
		DefaultTransactionDefinition def = new DefaultTransactionDefinition();
		TransactionStatus transaction = xmtm5TransactionManager.getTransaction(def);
		try {
			for (Ret_box retBox : boxList) {
				String boxId = retBox.getBox_id();
                String ship_box_id =retBox.getShip_box_id();
				CtSlimifRetBox5 ctSlimifRetBox = new CtSlimifRetBox5();
				ctSlimifRetBox.setVendorcode(XMTM_FACTORY_NAME);

				ctSlimifRetBox.setProductnumber(retBox.getLot_id_fk());
				ctSlimifRetBox.setDestination(retBox.getDestination());
				if(StringUtil.isNotBlank(ship_box_id))
				{
					ctSlimifRetBox.setBoxname(ship_box_id);
				}else{
					ctSlimifRetBox.setBoxname(boxId);
				}
				//ctSlimifRetBox.setBoxname(boxId);
				ctSlimifRetBox.setBoxquantity(retBox.getPrd_qty());

				ctSlimifRetBox.setReceiveflag("N");
				ctSlimifRetBox.setReleaseflag("N");
//				ctSlimifRetBox.setUnpackflag("N");
				ctSlimifRetBox.setDeliverytime(null);
//				ctSlimifRetBox.setReceivestate("N");

				woId = retBox.getWo_id_fk();

				setBoxThicknessProc(woId, ctSlimifRetBox);

//			
				List<Ret_tm_cus_prd_indt> retTmCusPrdIndtList = retTmCusPrdIndtDao.list(boxId);
				Map<Integer, String> sourceSlotSheetMap = new HashMap<Integer, String>();
				for (Ret_tm_cus_prd_indt retTmCusPrdIndt : retTmCusPrdIndtList) {
					sourceSlotSheetMap.put(retTmCusPrdIndt.getPosition(), retTmCusPrdIndt.getProductname());
				}

				List<Ret_prd_info> retPrdInfoList = retPrdInfoDao.getSheetList(boxId);

				String firstSheetId = retPrdInfoList.get(0).getPrd_seq_id();
				
					
				Ret_tm_cus_prd_in retTmCusPrdIn = retTmCusPrdInDao.get(boxId);
				if (retTmCusPrdIn == null) {
					String tmpBoxId = retTmCusPrdIndtDao.get(firstSheetId).getBoxname();
					retTmCusPrdIn = retTmCusPrdInDao.get(tmpBoxId);
					ctSlimifRetBox.setBoxrealid(retTmCusPrdIn.getBoxrealid());
				}
				
				if (retTmCusPrdIn != null){
					ctSlimifRetBox.setProducttype(retTmCusPrdIn.getProducttype());
					ctSlimifRetBox.setBoxtype(retTmCusPrdIn.getBoxtype());
					ctSlimifRetBox.setProductspecname(retTmCusPrdIn.getProductspecname());
					ctSlimifRetBox.setTargetproductspecname(retTmCusPrdIn.getTargetproductspecname());
					ctSlimifRetBox.setBoxrealid(retTmCusPrdIn.getBoxrealid());
				}

				Set<String> sheetIdSet = new HashSet<String>();
				for (Ret_prd_info rePrdInfo : retPrdInfoList) {
					sheetIdSet.add(rePrdInfo.getPrd_seq_id());
				}

				Map<String, List<Ret_prd_jge>> defectSheetMap = retPrdJgeDao.getDefectMapBySheets(sheetIdSet);

				Map<String, His_ret_prd_info> sheetStbiHisMap = hisRetPrdInfoDao
						.findSheetsStbiHistory(sheetIdSet.toArray(new String[sheetIdSet.size()]));
				
				Map<String, List<His_ret_prd_info>> sheetsHistory = hisRetPrdInfoDao.findSheetsHistory(sheetIdSet.toArray(new String[sheetIdSet.size()]));

				List<CtSlimifRetProduct5> ctSlimifRetProductList = new ArrayList<CtSlimifRetProduct5>();
				List<CtSlimifRetTrackHistory> ctSlimifRetTrackHistoryList = new ArrayList<CtSlimifRetTrackHistory>();

				List<Integer> slotList = new ArrayList<Integer>();

				List<CtSlimifRetDefectData5> ctSlimifRetDefectDataList = new ArrayList<CtSlimifRetDefectData5>();

				for (int i = 0; i < retPrdInfoList.size(); i++) {
					CtSlimifRetProduct5 ctSlimifRetProduct = new CtSlimifRetProduct5();
					
					
					
					Ret_prd_info sheet = retPrdInfoList.get(i);

					slotList.add(Integer.valueOf(sheet.getSlot_no()));
					int xCnt = sheet.getX_axis_cnt();
					int yCnt = sheet.getY_axis_cnt();
					int integration = xCnt * yCnt;
					ctSlimifRetBox.setIntegrationlevel(String.valueOf(integration));

					ctSlimifRetProduct.setVendorcode(XMTM_FACTORY_NAME);
					String sheetId = sheet.getPrd_seq_id();
					ctSlimifRetProduct.setProductname(sheetId);
					CtSlimifRetTrackHistory  ctSlimifRetTrackHistory =  ctSlimifRetTrackHistoryDao.getInforById(sheetId);
//					if(null ==ctSlimifRetTrackHistory){
//						
//					}else{
//						ctSlimifRetTrackHistoryList.add(ctSlimifRetTrackHistory);
//					}
					if(StringUtils.isNotBlank(ctSlimifRetTrackHistory.getPrd_seq_id())){
						ctSlimifRetTrackHistoryList.add(ctSlimifRetTrackHistory);
					}
					
//					ctSlimifRetProduct.setBoxname(sheet.getBox_id_fk());
					if(StringUtil.isNotBlank(ship_box_id))
					{
						ctSlimifRetProduct.setBoxname(ship_box_id);
					}else{
						ctSlimifRetProduct.setBoxname(boxId);
					}
					
//					ctSlimifRetProduct.setBoxname(retTmCusPrdIndtDao.get(sheetId).getBoxname());

					Integer slotNo = Integer.valueOf(sheet.getSlot_no());
					String sourceSheetId = sourceSlotSheetMap.get(slotNo);
					if (!StringUtils.isEmpty(sourceSheetId)) {
						ctSlimifRetProduct.setShipproduct(sourceSheetId);
					}
					ctSlimifRetProduct.setProductgrade(sheet.getGrade());
					ctSlimifRetProduct.setTrackintime(sheet.getAct_stb_timestamp());
					ctSlimifRetProduct.setTrackouttime(currentTimestamp);
					ctSlimifRetProduct.setPosition(Integer.valueOf(sheet.getSlot_no()));
					ctSlimifRetProduct.setDescription(sheet.getDs_recipe_id());
					ctSlimifRetProduct.setBoxrealid(ctSlimifRetBox.getBoxrealid());
					ctSlimifRetProductList.add(ctSlimifRetProduct);

					List<Ret_prd_jge> defectList = defectSheetMap.get(sheetId);

					if (defectList != null && !defectList.isEmpty()) {

						List<CtSlimifRetDefectData5> iqcDefectList = setIQCProc(defectMap, sheetStbiHisMap, sheetId,
								defectList);

						if (!iqcDefectList.isEmpty()) {
							ctSlimifRetDefectDataList.addAll(iqcDefectList);
						}
						
						List<CtSlimifRetDefectData5> jbDefectList = setProcDefect(defectMap,sheetsHistory,sheetId,"J007",defectList);//TODO
						if (!jbDefectList.isEmpty()) {
							ctSlimifRetDefectDataList.addAll(jbDefectList);
						}
						
						List<CtSlimifRetDefectData5> pgDefectList = setProcDefect(defectMap,sheetsHistory,sheetId,"QP02",defectList);//TODO
						if (!pgDefectList.isEmpty()) {
							ctSlimifRetDefectDataList.addAll(pgDefectList);
						}
						List<CtSlimifRetDefectData5> oqcDefectList = setOQCProc(defectMap, defectList);
						if (!oqcDefectList.isEmpty()) {
							ctSlimifRetDefectDataList.addAll(oqcDefectList);
						}
					}

				}

				ctSlimifRetDefectDataList.addAll(addCdpcCzPcProc(sheetIdSet));

				StringBuffer slotMap = new StringBuffer();
				for (int i = 0; i < retBox.getStd_qty(); i++) {
					slotMap.append(slotList.contains(i + 1) ? "O" : "X");
				}
				ctSlimifRetBox.setSlotmap(slotMap.toString());

				if (!ctSlimifRetDefectDataList.isEmpty()) {
					ctSlimifRetDefectData5Dao.saveBatch(ctSlimifRetDefectDataList);
				}

				ctSlimifRetProduct5Dao.saveBatch(ctSlimifRetProductList);
				ctSlimifRetTrackHistoryDao.saveBatch(ctSlimifRetTrackHistoryList);

				ctSlimifRetBox5Dao.save(ctSlimifRetBox);

				

			}
			xmtm5TransactionManager.commit(transaction);
		} catch (Exception ex) {
			xmtm5TransactionManager.rollback(transaction);
			throw ex;
		}

		outTrx.setRtn_code("0000000");
		outTrx.setRtn_mesg("SUCCESS");
		return outTrx;
	}

	private List<CtSlimifRetDefectData5> setProcDefect(
			Map<String, Bis_data> defectMap,
			Map<String, List<His_ret_prd_info>> sheetsHistory, String sheetId,
			String opeId,
			List<Ret_prd_jge> defectList) {
		
		List<His_ret_prd_info> sheetHistory = sheetsHistory.get(sheetId);
		Timestamp timestamp = null;
		
		for(His_ret_prd_info hisRetPrdInfo : sheetHistory){
			logger.info("cr_ope_id:{} , ope_id:{} , evt_cate : {}",hisRetPrdInfo.getCr_ope_id_fk(),opeId,hisRetPrdInfo.getEvt_cate());
			if(opeId.equals(hisRetPrdInfo.getCr_ope_id_fk()) && "LGOF".equals(hisRetPrdInfo.getEvt_cate())){
				timestamp = hisRetPrdInfo.getEvt_timestamp();
				logger.info("timestamp:{}",timestamp);
				break;
			}
		}
		
		List<Ret_prd_jge> procRetPrdJge = new ArrayList<Ret_prd_jge>();
		if(defectList==null){
		    List<CtSlimifRetDefectData5> list = new ArrayList<CtSlimifRetDefectData5>();
		    return list;
		}
		
		for(Ret_prd_jge defect : defectList){
			logger.info("{}",defect);
			logger.info("judgeTime: {}",defect.getJudge_timestamp());
			logger.info("evtTime: {}",timestamp);
			if(defect.getJudge_timestamp().before(timestamp)){
				procRetPrdJge.add(defect);
			}
		}
		return getDefectData(defectMap, defectList,false);
		
	}


	public List<CtSlimifRetDefectData5> setIQCProc(Map<String, Bis_data> defectMap,
			Map<String, His_ret_prd_info> sheetHisMap, String sheetId, List<Ret_prd_jge> defectList) {
		String opeId = getStbiOpe(sheetHisMap, sheetId);

		List<CtSlimifRetDefectData5> iqcDefectList = new ArrayList<CtSlimifRetDefectData5>();
		for (Ret_prd_jge defect : defectList) {

			if (!StringUtils.isEmpty(opeId) && defect.getOpe_id_fk().equals(opeId)) {

				CtSlimifRetDefectData5 ctSlimifRetDefectData = new CtSlimifRetDefectData5();
				ctSlimifRetDefectData.setVendorcode(XMTM_FACTORY_NAME);
				ctSlimifRetDefectData.setProductname(defect.getPrd_seq_id_fk());
				ctSlimifRetDefectData.setDefecttype("DEFECT");
				ctSlimifRetDefectData.setDefectxyaxis(defect.getDef_code1_lc());
				ctSlimifRetDefectData.setDefectside(defect.getDef_code1_sd());
				ctSlimifRetDefectData.setInspectoperation("IQC");

				Bis_data bisData = defectMap.get(defect.getDef_code1());
				if (bisData != null) {
					ctSlimifRetDefectData.setDefectdescription(bisData.getData_ext());
					ctSlimifRetDefectData.setDefectcode(bisData.getExt_5());
				}
				// ctSlimifRetDefectDataDao.save(ctSlimifRetDefectData);
				iqcDefectList.add(ctSlimifRetDefectData);
			}
		}
		return iqcDefectList;
	}

	public boolean isIQCDefect(Bis_data bisData){
		return "Y".equals(bisData.getExt_2()) ? true : false;
	}
	private String getStbiOpe(Map<String, His_ret_prd_info> sheetHisMap, String sheetId) {
		String opeId = null;
		His_ret_prd_info stbiSheetHistory = sheetHisMap.get(sheetId);

		if (stbiSheetHistory != null) {
			opeId = stbiSheetHistory.getCr_ope_id_fk();
		}
		return opeId;
	}
	
	
	

	private List<CtSlimifRetDefectData5> setOQCProc(Map<String, Bis_data> defectMap, List<Ret_prd_jge> defectList) {
		List<CtSlimifRetDefectData5> ctSlimifRetDefectDataList = getDefectData(defectMap, defectList,true);

		return ctSlimifRetDefectDataList;
		// if (!ctSlimifRetDefectDataList.isEmpty()) {
		// ctSlimifRetDefectDataDao.saveBatch(ctSlimifRetDefectDataList);
		// }
	}

	private List<CtSlimifRetDefectData5> getDefectData(Map<String, Bis_data> defectMap,
			List<Ret_prd_jge> defectList , boolean isOQC) {
		List<CtSlimifRetDefectData5> ctSlimifRetDefectDataList = new ArrayList<CtSlimifRetDefectData5>();

		for (Ret_prd_jge defect : defectList) {

			if (defect.getDef_code1_cnt() == -1) {
				continue;
			} else {
				boolean existFlg = false;
				for (Ret_prd_jge defect2 : defectList) {
					if (defect2.getDef_code1_lc().equals(defect.getDef_code1_lc())
							&& defect2.getDef_code1_sd().equals(defect.getDef_code1_sd())
							&& defect2.getDef_code1().equals(defect.getDef_code1())
							&& defect2.getDef_code1_cnt() == -1) {
						existFlg = true;
						break;
					}
				}

				if (existFlg) {
					continue;
				}
			}

			CtSlimifRetDefectData5 ctSlimifRetDefectData = new CtSlimifRetDefectData5();
			ctSlimifRetDefectData.setVendorcode(XMTM_FACTORY_NAME);
			ctSlimifRetDefectData.setProductname(defect.getPrd_seq_id_fk());
			ctSlimifRetDefectData.setDefecttype("DEFECT");
			ctSlimifRetDefectData.setDefectxyaxis(defect.getDef_code1_lc());
			ctSlimifRetDefectData.setDefectside(defect.getDef_code1_sd());
			ctSlimifRetDefectData.setInspectoperation("OQC");

			Bis_data bisData = defectMap.get(defect.getDef_code1());
			if (bisData != null) {
				ctSlimifRetDefectData.setDefectdescription(bisData.getData_ext());
				ctSlimifRetDefectData.setDefectcode(bisData.getExt_5());
				if(isOQC){
					if(isIQCDefect(bisData)){
						continue;
					}
				}
				
			}

			ctSlimifRetDefectDataList.add(ctSlimifRetDefectData);
		}
		return ctSlimifRetDefectDataList;
	}

	private void setBoxThicknessProc(String woId, CtSlimifRetBox5 ctSlimifRetBox) {
		List<Ret_wo> retWoList = retWoDao.getWo(woId);
		Ret_wo retWo = null;
		if (!retWoList.isEmpty()) {
			retWo = retWoList.get(0);
		}

		Double fromThickness = retWo.getFrom_thickness();
		Double toThickness = retWo.getTo_thickness();

		ctSlimifRetBox.setThickness(fromThickness == null ? "" : fromThickness.toString());
		ctSlimifRetBox.setTargetthickness(toThickness == null ? "" : toThickness.toString());
	}

	public List<CtSlimifRetDefectData5> addCdpcCzPcProc(Set<String> sheetIdSet) {
		List<Spc_ret_mfg_data> spcRetMfgDataList = spcRetMfgDataDao.getCsotSpcDataRecorderByShtIdsMesIds(sheetIdSet,
				mesIdList);
		Map<String, Spc_ret_mfg_data> cdpcEdcMap = new HashMap<String, Spc_ret_mfg_data>();
		Map<String, Spc_ret_mfg_data> czpcEdcMap = new HashMap<String, Spc_ret_mfg_data>();

		getEdcMap(spcRetMfgDataList, cdpcEdcMap, czpcEdcMap);

		List<CtSlimifRetDefectData5> ctSlimifRetDefectDataList = new ArrayList<CtSlimifRetDefectData5>();

		setCtDefectEdcEntityList(cdpcEdcMap, ctSlimifRetDefectDataList, "CDPC");
		setCtDefectEdcEntityList(czpcEdcMap, ctSlimifRetDefectDataList, "CZPC");

		return ctSlimifRetDefectDataList;
	}

	private void setCtDefectEdcEntityList(Map<String, Spc_ret_mfg_data> cdpcEdcMap,
			List<CtSlimifRetDefectData5> ctSlimifRetDefectDataList, String mesId) {

		Set<Entry<String, Spc_ret_mfg_data>> cdpcEntry = cdpcEdcMap.entrySet();
		for (Entry<String, Spc_ret_mfg_data> cdpc : cdpcEntry) {
			Spc_ret_mfg_data spcRetMfgData = cdpc.getValue();
			if (spcRetMfgData == null) {
				continue;
			}
			Integer dataCnt = spcRetMfgData.getData_cnt();
			for (int i = 0; i < dataCnt; i++) {
				CtSlimifRetDefectData5 ctSlimifRetDefectData = new CtSlimifRetDefectData5();
				ctSlimifRetDefectData.setVendorcode(XMTM_FACTORY_NAME);
				ctSlimifRetDefectData.setProductname(spcRetMfgData.getPrd_seq_id_fk());
				ctSlimifRetDefectData.setDefecttype(mesId);
				ctSlimifRetDefectData.setDefectposition(i + 1 + "");
				try {
					ctSlimifRetDefectData.setDefectcode(
							spcRetMfgData.getPropertyValue(Spc_ret_mfg_data.SPC_RET_MFG_DATA_VALUE_COLUMN_LIST.get(i)));
				} catch (Exception ex) {
					throw new ICIMException(ex);
				}
				ctSlimifRetDefectDataList.add(ctSlimifRetDefectData);
			}

		}
	}

	private void getEdcMap(List<Spc_ret_mfg_data> spcRetMfgDataList, Map<String, Spc_ret_mfg_data> cdpcEdcMap,
			Map<String, Spc_ret_mfg_data> czpcEdcMap) {
		for (Spc_ret_mfg_data newEdc : spcRetMfgDataList) {
			String newSheetId = newEdc.getPrd_seq_id_fk();
			if (newEdc.getMes_id_fk().equals("CDPC") ) {
				Spc_ret_mfg_data oldEdc = cdpcEdcMap.get(newSheetId);
				if (oldEdc == null) {
					cdpcEdcMap.put(newSheetId, newEdc);
				} else {
					if (newEdc.getRpt_timestamp().after(oldEdc.getRpt_timestamp())) {
						cdpcEdcMap.put(newSheetId, newEdc);
					}
				}
			} else if (newEdc.getMes_id_fk().equals("CZPC") ) {
				Spc_ret_mfg_data oldEdc = czpcEdcMap.get(newSheetId);
				if (oldEdc == null) {
					czpcEdcMap.put(newSheetId, newEdc);
				} else {
					if (newEdc.getRpt_timestamp().after(oldEdc.getRpt_timestamp())) {
						czpcEdcMap.put(newSheetId, newEdc);
					}
				}
			}

		}
	}

	private Map<String, Bis_data> getDefectMap(List<Ret_box> boxList) {
		Map<String, Bis_data> defectMap = new HashMap<String, Bis_data>();
		if (!boxList.isEmpty()) {
			List<Bis_data> bisDataList = bisDataList = bisDataDao.listData("DFCT", null, null, null, null, null, null,
					null, null);
			for (Bis_data bisData : bisDataList) {
				defectMap.put(bisData.getData_id(), bisData);
			}
		}
		return defectMap;
	}
}
